/**
 * 
 */
package com.wgo.precise.client.ui.controller.listeners;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.swt.SWTException;

import com.wgo.precise.client.ui.controller.RequirementPlugin;
import com.wgo.precise.client.ui.model.facade.IModelPersistable;
import com.wgo.precise.client.ui.model.facade.INodeParent;
import com.wgo.precise.client.ui.view.facade.IExtendedPart;
import com.wgo.precise.client.ui.view.util.ReflectionHelper;


/**
 * @author Petter L. H. Eide
 *
 */
public class PreciseSubject {
	
	public interface PreciseListener {}
	
	private HashMap<Class<? extends PreciseListener>,HashSet<? extends PreciseListener>> listenerMaps = new HashMap<Class<? extends PreciseListener>,HashSet<? extends PreciseListener>>();

	public void notifyModelUpdated(IModelPersistable item) {
		for ( IModelUpdateListener listener : getListener( IModelUpdateListener.class ) ) {
			try {
				listener.onModelUpdate(item);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyModelUpdated");
			}
		}
	}
	
	public void notifyModelChanged(IModelPersistable item) {
		for (IModelChangeListener listener : getListener( IModelChangeListener.class )) {
			try {
				listener.onModelChange(item);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyModelChanged");
			}
		}
	}
	public void notifyNewModelItemCreated(IModelPersistable item) {
		for (IModelChangeListener listener : getListener( IModelChangeListener.class )) {
			try {
				listener.onNewModelItemCreated(item);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyNewModelItemCreated");
			}
		}
		for (NewModelItemCreatedListener listener : getListener( NewModelItemCreatedListener.class )) {
			try {
				listener.onNewModelItemCreated(item);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyNewModelItemCreated");
			}
		}
	}
	public void notifyModelItemDeleted(IModelPersistable item, INodeParent parent){
		RequirementPlugin.getInstance().getEditorWindowManager().closeEditorHierarchy(item);
		for (IModelChangeListener listener : getListener ( IModelChangeListener.class )) {
			try {
				listener.onModelItemDeleted(item, parent);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyModelItemDeleted");
			}
		}
		for (ModelItemDeletedListener listener : getListener ( ModelItemDeletedListener.class )) {
			try {
				listener.onModelItemDeleted(item, parent);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifyModelItemDeleted");
			}
		}
	}
	
	public void notifySessionSaved() {
		for (SessionStatusListener listener : getListener( SessionStatusListener.class )) {
			try {
				listener.onSave();
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, "notifySessionSaved");
			}
		}
	}
	
	public <T extends PreciseListener> void addListener(Class<T> clazz, T listener) {
		getListener(clazz).add(listener);
	}
	
	public <T extends PreciseListener> void removeListener(Class<T> clazz, T listener) {
		getListener(clazz).remove(listener);
	}
	
//	public <T extends PreciseListener> void addListener( T listener , Class<T>... clazzes ) {
//		for (Class<T> clazz : clazzes ) {
//			getListener(clazz).add(listener);			
//		}
//	}
//	
//	public void removeListener( PreciseListener listener , Class<PreciseListener>... clazzes ) {
//		for (Class<PreciseListener> clazz : clazzes ) {
//			getListener(clazz).remove(listener);
//		}
//	}

	private <T extends PreciseListener> void notifyListeners(Class<T> listenerType , Method method, Object... args) {
		for (T listener : getListener( listenerType )) {
			try {
				ReflectionHelper.invoke(method.getName(), listener, method, args);
			} catch (SWTException e) {
				handlePartUpdateException(listener, e, method.getName());
			}
		}
	}
	
	@SuppressWarnings("unchecked") //TODO: verify that this cannot give ClassCastException
	private <T extends PreciseListener> Set<T> getListener(Class<T> clazz){
		HashSet<T> listeners = (HashSet<T>)listenerMaps.get(clazz);
		if (null == listeners) {
			listeners = new HashSet<T>() ;
			listenerMaps.put(clazz, listeners);
		}
		return listeners;
	}
	
	public void handlePartUpdateException(PreciseListener listener, SWTException e, String message){
		message = "Error updating editor: " + message ; 
		if (listener instanceof IExtendedPart) {
			message +=  " " + ((IExtendedPart)listener).getTitle();
		}
		RequirementPlugin.log(e, message);
	}
	
}
